#include <stdlib.h>
#include <GL/glut.h>
#include <stdio.h>
#include <string.h>
#include "cardMenu.h"
#include "cardGame.h"
#include "mesh.h"
#include "anim.h"

bool collide(Mesh, Mesh);

//CardGame::CardGame()
CardGame::CardGame(char type, int sel1, int sel2, int gStage)
{
	//Buffer
	char buffer[256];

	//Stages file
	FILE *fst = fopen("mod/stages", "r");
	
	//File failed
	if (!fst)
	{
		printf("Error opening file: mod/stages\n");
		return;
	}

	//Find stage
	int c = 0;
	while (fscanf(fst, "%s", buffer) != EOF)
	{
		//Comment - skip line
		if (buffer[0] == '#')
			fscanf(fst, "%*[^\n]"); else
		//Found a stage
		if (buffer[0] == '~')
		{
			//Found the stage of the current game
			if (c == gStage)
			{
				//Get stage's name and load stage
				fscanf(fst, "%s", buffer);
				stage.load(buffer, 0);

				//Stage has obstacles
				if (fscanf(fst, "%s", buffer) != EOF && buffer[0] == '{')
				while (1)
				{
					//Found end of obstacles
					fscanf(fst, "%s", buffer);
					if (buffer[0] == '}')
						break;

					//Create obstacle mesh
					Mesh mesh;

					mesh.load(buffer, 0);

					fscanf(fst, "%f %f", &mesh.loc.x, &mesh.loc.z);

					obstacle.push_back(mesh);
				}

				//Stage has enviroment objects
				if (fscanf(fst, "%s", buffer) != EOF && buffer[0] == '{')
				while (1)
				{
					//Found end of obstacles
					fscanf(fst, "%s", buffer);
					if (buffer[0] == '}')
						break;

					//Create enviroment object
					Mesh mesh;
					mesh.load(buffer, 0);

					fscanf(fst, "%f %f", &mesh.loc.x, &mesh.loc.z);

					env.push_back(mesh);

					//mesh.loc.y += 2.0f;
					//obstacle.push_back(mesh);
				}

				break;
			}
			//Another stage found
			else
			{
				//Move to next stage
				fscanf(fst, "%*[^~]");

				//Move counter
				c++;
			}
		}
	}

	//Close
	fclose(fst);

	//Parse file with stats
	FILE *file = fopen("mod/heroes", "r");

	//Failed to open file
	if (!file)
	{
		printf("Error opening file: mod/heroes\n");
		return;
	}

	//Count heroes found
	int counter = 0;
	while (fscanf(file, "%s", buffer) != EOF)
	{
		//Found comment
		if (buffer[0] == '#')
			//Skip line
			fscanf(file, "%*[^\n]"); else
		//Found hero
		if (buffer[0] == '~')
		{
			//Either player has selected this hero
			if (counter == sel1
			||  counter == sel2)
			{
				//Parse hero's path
				char path[256];
				fscanf(file, "%s", path);

				//Hero's stats
				int hp, dmg; 
				//int sp;
				float spd;
				fscanf(file, "%d", &hp);
				//fscanf(file, "%d", &sp);
				fscanf(file, "%f", &spd);
				fscanf(file, "%d", &dmg);

				//Effects
				/*
				std::vector<effect> effvec;
				while ( fscanf(file, "%s", buffer) != EOF && buffer[0] == '>')
				{
					//Variables
					int temp;
					effect eff;

					//Get [who]
					fscanf(file, "%s", &buffer);
					if ( strcmp(buffer, "ball" ) )
						eff.player = 0; else
					if ( strcmp(buffer, "self" ) )
						eff.player = 1; else
					if ( strcmp(buffer, "enemy") )
						eff.player = 2; 

					//Get [what]
					fscanf(file, "%d", &buffer);
					if ( strcmp(buffer, "speed"   ) )
						eff.stat = 0; else
					if ( strcmp(buffer, "health"  ) )
						eff.stat = 1; else
					if ( strcmp(buffer, "special" ) )
						eff.stat = 2; 

					//Get [how]
					if (eff.stat == 0)
					{
						float temp2;
						fscanf(file, "%f", &temp2);
						eff.amountf = temp2;
					}
					else
					{
						fscanf(file, "%d", &temp);
						eff.amountd = temp;
					}

					//Add effect to array
					effvec.push_back(eff);

					//printf("Effect: %ld\n", effvec.size());
				}*/
	
				//Player one chose this hero
				if (counter == sel1)
				{
					//Give data to p1
					p[0].load(path, 0);
					p[0].speed = spd;
					p[0].damage = dmg;
					health1.max = hp;
					//special1.max = sp;

					//Add effects
					/*unsigned int i;
					for (i = 0; i < effvec.size(); i++)
					{
						*if (effvec[i].player == 1)
							effvec[i].player = 1; else
						if (effvec[i].player == 2)
							effvec[i].player = 2; *
						//p[0].eff.push_back(effvec[i]);
					}*/
				}

				//Player two chose this hero
				if (counter == sel2)
				{
					//Give data to p[1]
					p[1].load(path, 1);
					p[1].speed = spd;
					p[1].damage = dmg;
					health2.max = hp;
					//special2.max = sp;

					/*
					unsigned int i;
					for (i = 0; i < effvec.size(); i++)
					{
						//If player == 1 then it's targeting self, so it changes to 2
						*if (effvec[i].player == 1)
							effvec[i].player = 2; else
						if (effvec[i].player == 2)
							effvec[i].player = 1; 
						p[1].eff.push_back(effvec[i]);*
					}*/
				}
			}

			//Skip until next line
			fscanf(file, "%*[^\n]");

			//Next hero
			counter++;
		}
	}

	//Close
	fclose(file);

	/* Players */

	//Player 1 - left
	p[0].loc.y = p[0].bound.y;
	p[0].loc.x = stage.loc.x -stage.bound.x +p[0].bound.x;
	p[0].mark = p[0].loc.z;

	//Player 2 - right
	p[1].loc.y = p[1].bound.y;
	p[1].loc.x = stage.loc.x +stage.bound.x -p[1].bound.x;
	p[1].mark = p[1].loc.z;

	/* Health bars */

	//Health bar 1
	health1.load("obj/bar.ply", 0);
	health1.cur = health1.max;
	health1.loc.x = (stage.loc.x -stage.bound.x) +health1.bound.x;

	//Health bar 2
	health2.load("obj/bar.ply", 0);
	health2.cur = health2.max;
	health2.loc.x = (stage.loc.x +stage.bound.x) -health1.bound.x;

	/* Special bars */

	//Special bar 1
	/*
	special1.load("obj/special_bar.ply", 0);
	special1.cur = 0;
	special1.loc.x = health1.loc.x +health1.bound.x +special1.bound.x;

	//Special bar 2
	special2.load("obj/special_bar.ply", 0);
	special2.cur = 0;
	special2.loc.x = health2.loc.x -health2.bound.x -special2.bound.x;
	*/

	//Make all bars be on the same line (on z axis)
	health1.loc.z = health2.loc.z = 
	//	special1.loc.z = special2.loc.z = 
			(stage.loc.z +stage.bound.z) +1.0f;

	/* Game Ball */
	ball.resetSpeed();
	ball.toX = 0.5f;
	ball.toZ = 0.5f;

	//Font
	font.setColorFront(0.9f, 0.327f, 0.689f);
	font.setColorBack (0.26f, 0.121f, 0.256f);
	font.setAlign(1);

	//DEBUG
	/*for (unsigned int i = 0; i < env.size(); i++)
	{
		//printf("Loc: %d\n", env[i].loc.x);
	}*/
}

void CardGame::input(unsigned char key, bool pressed)
{
	if (!anim.isRunning())
	switch (key)
	{
		case 27:
			anim.startFromStart();
			break;

		//Move upwards
		case 'w':
			//Pressed
			if (pressed)
				p[0].mark = stage.loc.z -stage.bound.z +p[0].bound.z;
			//Released
			else
				p[0].mark = p[0].loc.z;
			break;

		//Move downwards
		case 's':
			//Pressed
			if (pressed)
				p[0].mark = stage.loc.z +stage.bound.z -p[0].bound.z;
			//Released
			else
				p[0].mark = p[0].loc.z;
			break;

		//Activate skill
		case ' ':
			/*
			if (pressed)
				if (special1.cur == special1.max)
					activateSkill(0);
			*/
			break;

		case 'z':
			if (pressed)
			{
				health1.decrease(1);
				printf("health1: %d\n", health1.cur);
			}
			break;
		case 'x':
			if (pressed)
			{
				health1.increase(1);
				printf("health1: %d\n", health1.cur);
			}
			break;

		case 'v':
			if (pressed)
			{
				printf("Health  1: %d | Health  2: %d\n", health1 .cur, health2 .cur);
//				printf("Special 1: %d | Special 2: %d\n", special1.cur, special2.cur);
			}
			break;
	}
}

void CardGame::update()
{
	//Card animation
	if (anim.update())
		if (anim.isAtEnd())
		{
			delete card;
			card = new CardMenu;
			return;
		}

	//Artificial intelligence
	if (ball.toX   > 0
	&&  ball.loc.x > 0)
	{
		if (ball.loc.z < p[1].loc.z -p[1].bound.z
		||  ball.loc.z > p[1].loc.z +p[1].bound.z)
			p[1].mark = ball.loc.z;
	}

	//Move bricks towards their marks
	p[0].move();

	//Check if player 1 pushed the ball

	//Player touched ball
	if ( collide( ball, p[0] ) )
	{
		//Player 1 is going upwards
		if ( p[0].mark < p[0].loc.z )
		{
			//Ball has space to be pushed upwards
			if ( ball.loc.z -ball.bound.z -(stage.loc.z -stage.bound.z) +0.02f > p[0].speed )
				//Push ball upwards
				ball.loc.z = p[0].loc.z -p[0].bound.z -ball.bound.z -0.01f;
			//Ball has no more space to be pushed
			else
			{
				//Make ball stuck on wall
				ball.loc.z = stage.loc.z -stage.bound.z +ball.bound.z +0.01f;

				//Move player below ball
				p[0].loc.z = ball.loc.z +ball.bound.z +p[0].bound.z +0.01f;
			}
		}
		//Player 1 is going downwards
		else
		{
			//Ball has space to be pushed downwards
			if ( stage.loc.z +stage.bound.z -(ball.loc.z +ball.bound.z) +0.02f > p[0].speed )
				//Push ball downwards
				ball.loc.z = p[0].loc.z +p[0].bound.z +ball.bound.z +0.01f;
			//Ball has no more space to be pushed
			else
			{
				//Make ball stuck on wall
				ball.loc.z = stage.loc.z +stage.bound.z -ball.bound.z -0.01f;

				//Move player above ball
				p[0].loc.z = ball.loc.z -ball.bound.z -p[0].bound.z -0.01f;
			}
		}
	}

	p[1].move();

	//Player touched ball
	if ( collide( ball, p[1] ) )
	{
		//Player 2 is going upwards
		if ( p[1].mark < p[1].loc.z )
		{
			//Ball has space to be pushed upwards
			if ( ball.loc.z -ball.bound.z -(stage.loc.z -stage.bound.z) +0.02f > p[1].speed )
				//Push ball upwards
				ball.loc.z = p[1].loc.z -p[1].bound.z -ball.bound.z -0.01f;
			//Ball has no more space to be pushed
			else
			{
				//Make ball stuck on wall
				ball.loc.z = stage.loc.z -stage.bound.z +ball.bound.z +0.01f;

				//Move player below ball
				p[1].loc.z = ball.loc.z +ball.bound.z +p[1].bound.z +0.01f;
			}
		}
		//Player 2 is going downwards
		else
		{
			//Ball has space to be pushed downwards
			if ( stage.loc.z +stage.bound.z -(ball.loc.z +ball.bound.z) +0.02f > p[1].speed )
				//Push ball downwards
				ball.loc.z = p[1].loc.z +p[1].bound.z +ball.bound.z +0.01f;
			//Ball has no more space to be pushed
			else
			{
				//Make ball stuck on wall
				ball.loc.z = stage.loc.z +stage.bound.z -ball.bound.z -0.01f;

				//Move player above ball
				p[1].loc.z = ball.loc.z -ball.bound.z -p[1].bound.z -0.01f;
			}
		}
	}

	/* Ball update */
	
	//Y
	ball.loc.z += ball.speed *ball.toZ;

	//Ball is going upwards
	if ( ball.toZ < 0 )
	{
		//Ball touched top side of stage
		if (ball.loc.z -ball.bound.z < stage.loc.z -stage.bound.z)
		{
			//Bounce
			ball.loc.z = stage.loc.z -stage.bound.z +ball.bound.z +0.01f;
			ball.toZ *= -1;
		} else
		//Ball touched bottom side of first player
		if ( collide( ball, p[0] ) )
		{
			//Bounce
			ball.loc.z = p[0].loc.z +p[0].bound.z +ball.bound.z +0.01f;
			ball.toZ *= -1;
		} else
		//Ball touched bottom side of second player
		if ( collide( ball, p[1] ) )
		{
			//Bounce
			ball.loc.z = p[1].loc.z +p[1].bound.z +ball.bound.z +0.01f;
			ball.toZ *= -1;
		} else
		//Ball touched bottom side of obstacle
		for (unsigned int i = 0; i < obstacle.size(); i++)
			if ( collide( ball, obstacle[i]) )
			{
				ball.loc.z = obstacle[i].loc.z +obstacle[i].bound.z +ball.bound.z +0.01f;
				ball.toZ *= -1;
			}
	}
	//Ball is going downwards (or Z angle is 0, but this shouldn't happen)
	else
	{
		//Ball touched bottom side of stage
		if (ball.loc.z +ball.bound.z > stage.loc.z +stage.bound.z)
		{
			//Bounce
			ball.loc.z = stage.loc.z +stage.bound.z -ball.bound.z -0.01f;
			ball.toZ *= -1;
		} else
		//Ball touched top side of first player
		if ( collide( ball, p[0] ) )
		{
			//Bounce
			ball.loc.z = p[0].loc.z -p[0].bound.z -ball.bound.z -0.01f;
			ball.toZ *= -1;
		} else
		//Ball touched top side of second player
		if ( collide( ball, p[1] ) )
		{
			//Bounce
			ball.loc.z = p[1].loc.z -p[1].bound.z -ball.bound.z -0.01f;
			ball.toZ *= -1;
		} else
		//Ball touched top side of obstacle
		for (unsigned int i = 0; i < obstacle.size(); i++)
			if ( collide( ball, obstacle[i]) )
			{
				ball.loc.z = obstacle[i].loc.z -obstacle[i].bound.z -ball.bound.z -0.01f;
				ball.toZ *= -1;
			}
	}

	//X
	ball.loc.x += ball.speed *ball.toX;

	//Ball is going leftwards
	if (ball.toX < 0)
	{
		//Ball touched left side
		if (ball.loc.x -ball.bound.x < stage.loc.x -stage.bound.x)
		{
			//Decrease player 1's health
			health1.decrease(p[1].damage);
			if (health1.cur == 0 && !anim.isRunning())
				anim.startFromStart();
			ball.resetSpeed();

			//Bounce ball
			ball.loc.x = stage.loc.x -stage.bound.x +ball.bound.x +0.01f;
			ball.toX *= -1;
		} else
		//Ball touched first player (on the side, since ball just moved leftwards)
		if ( collide( ball, p[0] ) )
		{
			//Increase first player's specialbar
			//special1.increase(100);
			ball.increaseSpeed();
	
			//Bounce
			ball.loc.x = p[0].loc.x +p[0].bound.x +ball.bound.x +0.01f;
		
			//Calculate angle
			float zangle = (ball.loc.z -p[0].loc.z) /(p[0].bound.z +ball.bound.z) *0.7f;
			float xangle = 1.0f -( zangle > 0 ? zangle : -zangle);

			//Apply angle
			ball.toZ = zangle;
			ball.toX = xangle;
		} else 
		for (unsigned int i = 0; i < obstacle.size(); i++)
			if ( collide( ball, obstacle[i]) )
			{
				ball.loc.x = obstacle[i].loc.x +obstacle[i].bound.x +ball.bound.x +0.01f;
				ball.toX *= -1;
			}
	} 
	//Ball is going rightwards (this will also execute if ball's X angle is zero but this
	// shouldn't happen)
	else
	{
		//Ball touched right side
		if (ball.loc.x +ball.bound.x > stage.loc.x +stage.bound.x)
		{
			//Decrease player 2's health
			health2.decrease(p[0].damage);
			if (health2.cur == 0 && !anim.isRunning())
				anim.startFromStart();
			ball.resetSpeed();
	
			//Bounce ball
			ball.loc.x = stage.loc.x +stage.bound.x -ball.bound.x -0.01f;
			ball.toX *= -1;
		} else
		//Ball touched second player (on the side)
		if ( collide( ball, p[1] ) )
		{
			//Increase second player's specialbar
			//special2.increase(100);
			ball.increaseSpeed();

			//Bounce
			ball.loc.x = p[1].loc.x -p[1].bound.x -ball.bound.x -0.01f;

			//Calculate angle
			float zangle = (ball.loc.z -p[1].loc.z) /(p[1].bound.z +ball.bound.z) *0.7f;
			float xangle = -1.0f +( zangle > 0 ? zangle : -zangle);

			//Apply angle
			ball.toZ = zangle;
			ball.toX = xangle;
		} else
		for (unsigned int i = 0; i < obstacle.size(); i++)
			if ( collide( ball, obstacle[i]) )
			{
				ball.loc.x = obstacle[i].loc.x -obstacle[i].bound.x -ball.bound.x -0.01f;
				ball.toX *= -1;
			}
	}
}

void CardGame::draw()
{
	Card::draw();

	//Camera movement
	glTranslatef(0.0f, -0.0f, -20.0f);
	glRotatef(60.0f, 1.0f, 0.0f, 0.0f);

	//Draw Stage
	stage.draw();

	//Draw players
	p[0].draw();
	p[1].draw();

	//Draw ball
	ball.draw();

	//Draw bars
	health1.draw();
	health2.draw();
	/*
	special1.draw();
	special2.draw();
	*/

	/* Debug - drawing player's special bar as text */
	glPushMatrix();
	glTranslatef(-5.0f, 6.0f, 7.0f);
	glRotatef(-45.0f, 1.0f, 0.0f, 0.0f);
	font.drawInt(health1 .cur);
	/*glTranslatef(2.0f, 0.0f, 0.0f);
	font.drawInt(special1.cur);*/
	glTranslatef(10.0f, 0.0f, 0.0f);
	/*font.drawInt(special2.cur);
	glTranslatef(2.0f, 0.0f, 0.0f);*/
	font.drawInt(health2 .cur);
	glPopMatrix();

/*	glPushMatrix();
	glTranslatef(-5.0f, 6.0f, 5.0f);
	glRotatef(-45.0f, 1.0f, 0.0f, 0.0f);
	font.drawInt(health1 .max);
	glTranslatef(2.0f, 0.0f, 0.0f);
	font.drawInt(special1.max);
	glTranslatef(6.0f, 0.0f, 0.0f);
	font.drawInt(special2.max);
	glTranslatef(2.0f, 0.0f, 0.0f);
	for font.drawInt(health2 .max);
	glPopMatrix();*/

	//Draw environment
	for (unsigned int i = 0; i < env.size(); i++)
		env[i].draw();

	//Obstacles
	for (unsigned int i = 0; i < obstacle.size(); i++)
		obstacle[i].draw();
}

/* Check if the two objects collide
 * parameters:
 * loc1 is the position of object one
 * bound1 is it's bounding box
 * loc2 is the position of object two
 * bound2 is it's bounding box
 */
bool collide(Mesh mesh1, Mesh mesh2)
{
	//X
	if (mesh1.loc.x +mesh1.bound.x > mesh2.loc.x -mesh2.bound.x
	&&  mesh1.loc.x -mesh1.bound.x < mesh2.loc.x +mesh2.bound.x
	//Y - For complete collision it should check Y too, but in this instance it's not needed
	// because all objects are on the same Y-axis
	//&&  loc1.y +bound1.y > loc2.y -bound2.y
	//&&  loc1.y -bound1.y < loc2.y +bound2.y
	//Z
	&&  mesh1.loc.z +mesh1.bound.z > mesh2.loc.z -mesh2.bound.z
	&&  mesh1.loc.z -mesh1.bound.z < mesh2.loc.z +mesh2.bound.z
	)
		//Collide
		return true;

	//Doesn't collide
	return false;
}
/*
void CardGame::activateSkill(unsigned char pn)
{
	Effect e;



	switch (p[pn].effect)
	{
		case 0:
		case 1:
		case 2:
			break;
	}

	//The player that activated this loses their special points
	if (pn == 0)
		special1.cur = 0;
	else
		special2.cur = 0;

	effect.push_back(e);
}*/
